메뉴 바로가기 검색 및 카테고리 바로가기 본문 바로가기

한빛출판네트워크

IT/모바일

새로운 사용자 ID를 추가하는 배치작업

한빛미디어

|

2002-08-07

|

by HANBIT

8,611

저자: 『Learning the Korn Shell, 2nd Edition』의 공동 저자 아놀드 로빈스(Arnold Robbins), 역 신동섭

흔하게 볼 수 있는 시스템 관리 작업 중 하나가 바로 새로운 사용자를 추가하는 작업이다. 규모가 큰 회사나 대학의 중앙 컴퓨터 서버와 같은 대규모 인스톨에서 사용자를 추가하는 작업은 "배치(batch)" 작업을 통해 가장 잘 수행할 수 있는데 이는 스크립트를 사용하여 자동적으로 된다. 예를 들어 국립대학에서 새 학기가 시작되면 신입생은 수백 명에서 수천 명에 이르게 된다. 이러한 신입생들의 계정을 일일이 수작업으로 만드는 것은 거의 불가능하다. 따라서 우리는 이 작업을 자동으로 해 줄 수 있는 자동화 작업이 필요하다.

유닉스 시스템에서 사용자 계정들은 단일 사용자 ID번호(UID)를 가져야 한다. 유닉스는 UID로 사용자들을 구분하고 그 파일을 적용하고 권한을 프로세싱하는데 이를 사용한다. 새로운 사용자들을 추가할 때 우리는 각각의 새로운 사용자에게 이전에 사용된 적이 없는 고유한 UID번호를 할당해야 한다.

새로운 UID를 할당하는 접근방법 중 하나는 가장 높은 수의 UID를 채택하여 거기서부터 증가시켜 나가는 것이다. 따라서 UID는 가장 큰 값을 갖게 되지만 값에는 반드시 한계가 있게 된다. 특히 어떤 시스템은 최대값을 16비트 unsigned형 정수인 65535로 제한한다. 큰 규모의 환경에서 "가장 큰 값을 택한 후 이를 증가시켜 나가는" 접근방법을 사용할 경우 얼마 안가서 선택할 수 있는 범위의 수들이 고갈될 것이라는 것은 누구나 쉽게 추측할 수 있는 사실이다.

시간이 지나면 여러 개의 사용자 계정이 하나씩 삭제될 것이라는 사실도 고려해야 한다. 예를 들어 학생이 졸업하여 취업을 한 경우, 그 학생의 계정은 남겨둘 필요가 없다. 최소한 그 학생과 관련된 모든 그들 파일들을 제거하고 그 시스템의 패스워드 파일에서 이러한 학생들의 엔트리들을 제거해야 한다.

이와 같은 상황에서 좀 더 현명한 접근방법은 할당된 UID번호의 범위 내에 사용하지 않는 번호가 있을 것이라는 사실을 미리 인지하는 것이다. 새로운 계정을 생성할 때 UID공간 내에 존재하지만 사용되지 않은 UID번호들을 할당하는 것이다. 아래 스크립트는 이러한 생각을 구현한 것이다. 이것은 사용자를 추가하기위한 좀 더 큰 범위의 스크립트중 한 요소로 사용된다. 이 스크립트의 사용 예는 다음과 같다.
newuids [-c N]
이 프로그램의 기본 동작은 /etc/passwd 패스워드 파일 내에서 사용할 수 있는 첫 번째 사용되지 않은 UID를 출력하는 것이다. 만약 N 카운트를 가진 -c 옵션을 사용하게 되면 사용되지 않은 UID번호들을 N개 출력한다.

프로그램은 ksh과 기본 사용법을 설명한 초기 설명을 불러오기 위해 !# 라인으로 시작한다:
#! /bin/ksh

# newuids --- print one or more unused uids
#
# usage:
#       newuids [-c N]
#       -c N            print N unused uids
다음에는 몇 개의 변수 할당내용과 프로그램이 종료될 때 임시 파일을 지우기 위한 트랩 명령이 오게된다.
PASSWD=${PASSWD:-/etc/passwd}
TMPFILE=/tmp/uidlist$$

trap "rm -f $TMPFILE" EXIT HUP TERM     # clean up on exit or signal
그 다음에는 인자(argument)를 파싱(parsing)하게된다. 우리는 하나의 가능한 옵션을 처리하기 위해 내장된 getopts 명령을 사용한다. 단지 하나의 옵션일 경우에는 반드시 사용할 필요가 없는 기술이지만 시간이 흐르면서 더 많은 옵션이 추가될 경우 더 편리하게 사용될 수 있기 때문이다. 미리 계획해서 손해 보는 일은 없다.
count=1         # how many uids to print

# parse arguments, let ksh issue diagnostics
# and exit if need be
while getopts "c#" opt
do
        case $opt in
        c)      count=$OPTARG ;;
        esac
done
유닉스 /etc/passwd 파일은 한 라인당 한 명의 사용자라는 시스템 사용자들을 나타낸다. 각 라인은 사용자 명, 암호화된 패스워드 필드, UID, 그룹 ID, 사용자의 완전한 이름(full name), 홈 디렉토리(그 사용자를 위한 $HOME 초기값), 마지막으로 로그인 과 같은 일곱 개의 필드로 구성되며 이 필드들은 콜론으로 구분된다. 예를 들면 아래와 같다.
arnold:xyzzy42:2076:10:Arnold D. Robbins:/home/arnold:/bin/ksh
사용되지 않은 UID수를 발견하려면 우리는 패스워드 파일에서 사용하고 있는 UID번호들을 순차적으로 리스트하는 작업부터 해야 한다. UID번호 추출은 awk으로 할 수 있으며 그러한 리스트를 정렬하는 작업은 sort로 할 수 있다. 정렬된 리스트는 $TMPFILE이라는 파일명으로 저장된다.
awk -F: "{ print $3 }" $PASSWD | # generate list of uids
sort -n -u > $TMPFILE            # sort numerically, remove duplicates
이제 정렬된 리스트를 인덱스된 배열 uid리스트로 읽을 수 있으며 변수 totalids 내의 총 요소의 수를 저장한다.
set -A uidlist $(< $TMPFILE)            # save in indexed array

totalids=${#uidlist[*]}                 # total number of uids
이 시점에서 모든 셋업은 완료된다. 남아있는 모든 것은 비연속적인 한 쌍의 엔트리드를 발견하는 배열위의 루프이다. 하나가 발견되면 스크립트는 그 엔트리 안의 첫 번째 엔트리와 두 번째 값 사이에 모든 값들을 출력해준다. 변수 카운트는 각 회마다 감소하게 되어 결국 그 프로그램은 사용되지않은 UID의 요구한 수보다 더 많은 수는 확실히 출력하지 않을 것이라는 것을 알 수 있다.
# loop over ids, finding non-contiguous ones
for ((i = 2; i <= totalids; i++))
do
        if (( uidlist[i-1] + 1 != uidlist[i] ))
        then
                for ((j = uidlist[i-1] + 1; j < uidlist[i]; j++))
                do
                        print $j
                        if (( --count == 0 ))
                        then
                                break 2
                        fi
                done
        fi
done
이 루프를 주목해야 할 첫 번째 이유는 콘 셸(Korn Shell)의 ((...)) 구조로 만드는 것이 사용상에 있어 부담스럽다는 점이다. 특히 ((...)) 안의 변수들은 자신의 값을 얻기 위해 달러 표시를 할 필요가 없으며 하위스크립트를 위해서 숫자 표현들을 사용할 수 있다. (단지 ((...)) 안에 있는 것으로 제한되지는 않기 때문에 숫자 표현을 사용할 수 있음.) --count 표현은 그 값을 테스트하기 전에 count를 감소시킨다. 만약 count가 1에서 시작된다면 이는 0이 될 것이다. 더 높은 초기값도 그것이 0이 될 때까지 감소될 것이다.


Learning the Korn Shell, 2nd Edition

참고 도서

Learning the Korn Shell, 2nd Edition
Bill Rosenblatt, Arnold Robbins




다음으로 알아두어야 하는 것은 break 2 사용법으로 이는 for루프를 2단계까지 빠져나간다. 이 외에도 C, C++이나 awk같은 언어에서는 사용할 수 없는 편리한 특징이다. 또한 문제가 발생할 수 있는 goto (Bsh(Bourne-derived shells)에는 존재하지 않음)를 사용하지 않아도 되는 장점이 있다.

이제 끝이다! 브라우저에서 자유롭게 자르고 붙일 수 있는 완전한 스크립트는 다음과 같다.
#! /bin/ksh

# newuids --- print one or more unused uids
#
# usage:
#       newuids [-c N]
#       -c N            print N unused uids

PASSWD=${PASSWD:-/etc/passwd}
TMPFILE=/tmp/uidlist$$

trap "rm -f $TMPFILE" EXIT HUP TERM     # clean up on exit or signal

count=1         # how many uids to print

# parse arguments, let ksh issue diagnostics
# and exit if need be
while getopts "c#" opt
do
        case $opt in
        c)      count=$OPTARG ;;
        esac
done

awk -F: "{ print $3 }" $PASSWD |  # generate list of uids
sort -n -u > $TMPFILE             # sort numerically, remove duplicates

set -A uidlist $(< $TMPFILE)      # save in indexed array

totalids=${#uidlist[*]}           # total number of uids

# loop over ids, finding non-contiguous ones
for ((i = 2; i <= totalids; i++))
do
        if (( uidlist[i-1] + 1 != uidlist[i] ))
        then
                for ((j = uidlist[i-1] + 1; j < uidlist[i]; j++))
                do
                        print $j
                        if (( --count == 0 ))
                        then
                                break 2
                        fi
                done
        fi
done
이 스크립트는 업데이트할 수 있다. 예를 들어 가장 작게 허용된 UID번호를 지정하기위해 한 옵션을 추가한다고 생각해보자. 이 스크립트는 UID 숫자들의 범위가 서로 다른 학과나 학교로 할당되도록 정책지워진 중앙 서버에서 유용하게 사용될 수 있다.

이밖에도 newuids -man으로부터 좋은 결과를 얻거나 긴 옵션을 허용하기위해 콘 셸의 getopts 명령어의 향상된 능력들을 사용할 수도 있다.
아놀드 로빈스(Arnold Robbins)는1980년부터 유닉스 시스템에 관한 업무를 담당하는 프로 프로그래머이자 기술분야 저자이다.
TAG :
댓글 입력
자료실

최근 본 책0